package com.example.mybrowser;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
//import java.sql.Date;

import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.example.mybrowser.Pack.PackageEntry;

import android.R.integer;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.*;

public class MobileCache {
	
	private String CachePath;
	private int Capacity;
	private int MemoryUsed;
	private String LastUpdateTime;//yyyy-mm-dd hh:mm:ss
	private SQLiteDatabase CacheDatabase; 
	public String fileDir;

	
	public MobileCache(String _Path, AssetManager asset)
	{
		fileDir = _Path;
		InitializeCache(asset);
	}
	
	private void FirstTimeInitialize(AssetManager asset)
	{
		String filepathroot = fileDir + "/Files";
		File cacheFile = new File(filepathroot);
		if (!cacheFile.exists())
			cacheFile.mkdirs();
		
		String[] nextlevel = {"", "/0", "/1", "/2", "/3", "/4", "/5", "/6", "/7", "/8", "/9", "/a", "/b", "/c", "/d", "/e", "/f"};
		int i,j;
		for (i=1;i<=16;i++)
		{
			for (j=0;j<=16;j++)
			{
				String x = filepathroot+nextlevel[i]+nextlevel[j];
				cacheFile = new File(x);
				if (!cacheFile.exists())
					cacheFile.mkdirs();
			}
		}
		
		InputStream mFileIn = null;
		FileOutputStream mFileOut;

		try
		{
			mFileIn = asset.open("MobileCache.db");
			mFileOut = new FileOutputStream(fileDir+"/MobileCache.db");

			int readedBytes;
			byte[] buf = new byte[128];
			while ((readedBytes = mFileIn.read(buf)) > 0) 
			{
				mFileOut.write(buf, 0, readedBytes);
			}
			mFileOut.flush();

			mFileIn.close();
			mFileOut.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}

	}
	
	private void InitializeCache(AssetManager asset)
	{
		String dbPath = fileDir+"/MobileCache.db";
		if (!new File(dbPath).exists())
			FirstTimeInitialize(asset);
		CacheDatabase = SQLiteDatabase.openOrCreateDatabase(dbPath, null);
		MemoryUsed = 0;
	}
	
	public boolean AddFile(String URL, String FullHTTPResponse, byte[] data, int offset, int size) throws IOException{
	
		CacheEntry temp = new CacheEntry();
		temp.URL = URL;
		temp.Size = -1;
		temp.Type = "N/A";
		temp.CacheControl = new String("N/A");
		temp.encoding = new String("NoCompress");
		temp.HTTPResponse = FullHTTPResponse;
		
		String[] HTTPResponse = FullHTTPResponse.split("\r\n");
		for( int i = 0; i < HTTPResponse.length; i++ ){
			if(HTTPResponse[i].contains("Content-Length")){
				String[] strings = null;
				strings = HTTPResponse[i].split(":");
				temp.Size = Integer.parseInt(strings[1].substring(1)); 
				continue;
			}
			
			if(HTTPResponse[i].contains("Cache")){
				String[] strings = null;
				strings = HTTPResponse[i].split(":");
				temp.CacheControl = strings[1].substring(1); 
				continue;
			}

			if(HTTPResponse[i].contains("Content-Type")){
				String[] strings = null;
				strings = HTTPResponse[i].split(":");
				temp.Type = strings[1].substring(1); 
				continue;
			}			
			if(HTTPResponse[i].contains("Content-Encoding")){
				String[] strings = null;
				strings = HTTPResponse[i].split(":");
				temp.encoding = strings[1].substring(1); 
				continue;
			}
		}
		
		temp.Valid = true;
		temp.MD5 = MD5CheckSum.getMD5byBytes(data, offset, size);
		
		StoreFile(temp, data, offset, size);
		return true;
		
	}
	
	public boolean AddFile(PackageEntry packageEntry) throws IOException{
		
		
		CacheEntry temp = new CacheEntry();
		temp.URL = packageEntry.URL;
		temp.Size = -1;
		temp.Type = "N/A";
		temp.CacheControl = new String("N/A");
		temp.encoding = new String("NoCompress");
		temp.HTTPResponse = packageEntry.Response;
		
		String[] HTTPResponse = packageEntry.Response.split("\r\n");
		for( int i = 0; i < HTTPResponse.length; i++ ){
			if(HTTPResponse[i].contains("Content-Length")){
				String[] strings = null;
				strings = HTTPResponse[i].split(":");
				temp.Size = Integer.parseInt(strings[1].substring(1)); 
				continue;
			}
			
			if(HTTPResponse[i].contains("Cache")){
				String[] strings = null;
				strings = HTTPResponse[i].split(":");
				temp.CacheControl = strings[1].substring(1); 
				continue;
			}

			if(HTTPResponse[i].contains("Content-Type")){
				String[] strings = null;
				strings = HTTPResponse[i].split(":");
				temp.Type = strings[1].substring(1); 
				continue;
			}			
			if(HTTPResponse[i].contains("Content-Encoding")){
				String[] strings = null;
				strings = HTTPResponse[i].split(":");
				temp.encoding = strings[1].substring(1); 
				continue;
			}
		}
		
		temp.Valid = true;
		temp.MD5 = packageEntry.MD5;
		
		StoreFile(temp, packageEntry.Content, packageEntry.UseCache);
		return true;
		
	}
	
	@SuppressLint("SimpleDateFormat")
	private boolean StoreFile(CacheEntry tempEntry, byte[] FileContent, int useCache) throws IOException{
		
		String relativePath = tempEntry.MD5.charAt(0)+"/"+tempEntry.MD5.charAt(1)+"/"+tempEntry.MD5;
		String filepath=fileDir+"/Files/"+relativePath;

		if (useCache == 0)
		{
			File cacheFile = new File(filepath);
	        FileOutputStream fos = new FileOutputStream(cacheFile);  
	        fos.write(FileContent);
	        fos.close();
		}
		
        CacheDatabase.execSQL("DELETE FROM [SQLcache] WHERE URL='"+tempEntry.URL+"'");
        
		Date updatetime = new Date(); 
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String NowTime = dateFormat.format(updatetime); 
		System.out.println(NowTime); 
        ContentValues values = new ContentValues();
        values.put("URL", tempEntry.URL );
        values.put("Size", tempEntry.Size);
        values.put("CacheControl", tempEntry.CacheControl);
        values.put("Type",tempEntry.Type);
        values.put("Valid", true);
        values.put("FilePath",relativePath);
        values.put("MD5", tempEntry.MD5);
        //values.put("UpdateTime", NowTime);
        values.put("CompressMethod", tempEntry.encoding);
        values.put("ResponseHeader", tempEntry.HTTPResponse);
        
        CacheDatabase.insertOrThrow("SQLcache", null, values);
        
        MemoryUsed += tempEntry.Size;
        if( IsExceedMemory() )
           CleanUp();
		
		return true;
	}
	
	@SuppressLint("SimpleDateFormat")
	private boolean StoreFile(CacheEntry tempEntry, byte[] FileContent, int offset, int size) throws IOException{
		
		String relativePath = tempEntry.MD5.charAt(0)+"/"+tempEntry.MD5.charAt(1)+"/"+tempEntry.MD5;
		String filepath=fileDir+"/Files/"+relativePath;

		File cacheFile = new File(filepath);
        FileOutputStream fos = new FileOutputStream(cacheFile);  
        fos.write(FileContent, offset, size);
        fos.close();  
		
        CacheDatabase.execSQL("DELETE FROM [SQLcache] WHERE URL='"+tempEntry.URL+"'");
        
		Date updatetime = new Date(); 
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String NowTime = dateFormat.format(updatetime); 
		System.out.println(NowTime); 
        ContentValues values = new ContentValues();
        values.put("URL", tempEntry.URL );
        values.put("Size", tempEntry.Size);
        values.put("CacheControl", tempEntry.CacheControl);
        values.put("Type",tempEntry.Type);
        values.put("Valid", true);
        values.put("FilePath",relativePath);
        values.put("MD5", tempEntry.MD5);
        //values.put("UpdateTime", NowTime);
        values.put("CompressMethod", tempEntry.encoding);
        values.put("ResponseHeader", tempEntry.HTTPResponse);
        
        CacheDatabase.insertOrThrow("SQLcache", null, values);
        
        MemoryUsed += tempEntry.Size;
        if( IsExceedMemory() )
           CleanUp();
		
		return true;
	}
	
	private boolean IsFileExist(String URL){
		
		String[] columns = {"FilePath"};
		Cursor results = CacheDatabase.query("SQLCache", columns,"URL="+URL, 
							null, null, null, null);
		if(results.getCount() < 1)
			return false;
		else 
			return true;
	}
	
	public MyHTTPResponse GetFileContent(String URL)
	{
		if (URL.startsWith("http://"))
		{
			URL = URL.substring(7);
		}
		MyHTTPResponse myHTTPResponse = new MyHTTPResponse();

		Cursor cursor = CacheDatabase.rawQuery("SELECT * FROM [SQLcache] WHERE URL='"+URL+"'", null);
		if (cursor.moveToNext()) 
		{
			String RelFilePath = cursor.getString(5);
			myHTTPResponse.header = cursor.getString(8);
			myHTTPResponse.ResourcePath=fileDir+"/Files/"+RelFilePath;
		}
		else 
		{
			String theres;
			theres = "";
			theres += "HTTP/1.1 200 OK\r\n";
			theres += "Date: Mon, 7 Apr 2014 23:59:59 GMT\r\n";
			theres += "Content-Type: text/html;charset=ISO-8859-1\r\n";
			theres += "Content-Length: 64\r\n";
			theres += "\r\n";
			theres += "<html><body><h1>SmartBrowser said: No Cache!</h1></body></html>\0\r\n";
			myHTTPResponse.header = theres;
			myHTTPResponse.ResourcePath = "NULL";
		}
		return myHTTPResponse;
	}
	
	private boolean DeleteFile(String URL){
		
		return false;
	}
	
	private void CleanUp(){
		
	}
	 
	private boolean IsExceedMemory(){
		if(MemoryUsed > Capacity)
			return true;
		else
			return false;
	}

}
